#include <QThread>
#include <QSet>
#include <QWaitCondition>
#include <QThreadPool>
#include <QVariant>
#include "AnimMontageUtils.h"
#include "AnimMontage.h"
#include "AnimMontage_p.h"

class MontageManger
{
public:
    typedef std::function<void()> FuncType;

    static MontageManger* instance(){
        static MontageManger i;
        return &i;
    }

    void postToBackEnd(AnimMontage* m,FuncType func){
        {
            QMutexLocker locker(&mutex);
            montages[m] ++;
        }
        QThreadPool::globalInstance()->start([=](){
            func();
            {
                QMutexLocker locker(&mutex);
                montages[m] --;
                wait.notify_all();
            }
        });
    }

    void registerObj(AnimMontage* montage){
        QMutexLocker locker(&mutex);
        montages[montage] = 0;
    }

    void unregisterObj(AnimMontage* montage){
        QMutexLocker locker(&mutex);
        //在引用计数归零前该对象无法被析构，析构过程会被阻塞住
        while(montages[montage] != 0)
        {
            wait.wait(&mutex);
        }
        montages.remove(montage);
    }

private:
    QMutex mutex;
    QWaitCondition wait;
    QMap<AnimMontage*,int> montages;//记录对象的存活情况以及引用计数，
};


AnimMontage::AnimMontage():_P(new AnimMontagePrivate(this))
{
    MontageManger::instance()->registerObj(this);
}

AnimMontage::~AnimMontage()
{
    MontageManger::instance()->unregisterObj(this);
    delete _P;
}

QObject *AnimMontage::getTarget() const
{
    return target;
}

void AnimMontage::setTarget(QObject *newTarget)
{
    if (target == newTarget)
        return;
    target = newTarget;
    onTargetUpdate();
    emit targetChanged();
}

PoseNode *AnimMontage::getSource() const
{
    return source;
}

void AnimMontage::setSource(PoseNode *newSource)
{
    if (source == newSource)
        return;
    source = newSource;
    emit sourceChanged();
}

bool AnimMontage::getRunning() const
{
    return running;
}

void AnimMontage::setRunning(bool newRunning)
{
    if (running == newRunning)
        return;
    running = newRunning;

    update();

    emit runningChanged();
}

void AnimMontage::update()
{
    if(running)
    {
        if(!active)
        {
            active = true;
            postFrame();
        }
    }
}

void AnimMontage::onTargetUpdate()
{
    idMap = {};

    auto ret = AnimMontageUtils::groupById(target);

    for(auto i:ret.keys())
    {
        idMap[i] = ret[i];
    }
}

void AnimMontage::postFrame()
{
    MontageManger::instance()->postToBackEnd(this,[=](){
        Pose ret;
        if(source)
        {
            ret = source->getEntry();
        }

        this->metaObject()->invokeMethod(this,[=](){
            if(running)
            {
                applyEntrys(ret);
                postFrame();//计算下一帧姿态
            }
            else{
                active = false;
            }
        });

    });

}

template<typename T>
void setValue(QObject* o,const char* name,const T& value){
    if(value && o->property(name) != value)
    {
        o->setProperty(name,value.value());
    }
}

void AnimMontage::applyEntrys(const Pose &entrys)
{
    for(const auto& targetId:entrys.keys())
    {
        const auto &props = entrys[targetId];
        auto target = idMap.value(targetId);
        if(target)
        {
            setValue(target,"rotation",props.rotation);
            setValue(target,"position",props.position);
            setValue(target,"scale",props.scale);
        }
    }
}
